﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace Parser
{
    /// <summary>
    /// Class reads and uses parsing methods uing instructions taken from XML file.
    /// 
    /// </summary>
    public class FileReaderParser
    {

        private XmlParser _xmlParser;
        private IEnumerable<string> _sourceFileNames;

        /// <summary>
        /// constructor, takes the name of the xml instructions file.
        /// </summary>
        /// <param name="xmlFileName"></param>
        public FileReaderParser(string xmlFileName)
        {
            _xmlParser = new XmlParser(xmlFileName);
            _sourceFileNames = _xmlParser.FileNames;

        }

        /// <summary>
        /// Names of the source files listed in the xml instructions file.
        /// used to select a data source for parsing. 
        /// </summary>
        public IEnumerable<string> SourceFileNames
        {
            get { return _sourceFileNames; }
        }

        /// <summary>
        /// returns the list of columns of theselected source file.
        /// </summary>
        /// <param name="fileName">sourcefile name</param>
        /// <returns></returns>
        public IEnumerable<string> getSourceColumns(string fileName)
        {
            return _xmlParser.getColumnNames(fileName);
        }

        /*

                public  void load(string sourceFileName)
                {
                    //loading the text
                    List<List<string>> text = readSourceFile(sourceFileName);
            
                    foreach (List<string> line in text)
                    { //user id | item id | rating | timestamp


               


                    }
                }
                        public void loadData(string sFileName)
                { //ID	Name	Date	URL	Genres	Cast	Director
                    //loading the text
                    List<List<string>> text = readFile(sFileName);
            
                    //entering data to the structure
                    foreach (List<string> line in text)
                    {
                        if (line[1] == "unknown")
                            continue;
                        //adding the movie
                        //Movie mov = new Movie(line);
                        //this.Movies.Add(mov.MovieID, mov);

                    }//foreach
                }
         * */

        /// <summary>
        /// reads the file and parses the words into list of lists (preparing for further data structure insertion).
        /// </summary>
        /// <param name="text_filename">a source file selected from the list of sources listed in the XML</param>
        /// <returns></returns>
        public List<List<string>> readSourceFile(string text_filename, BackgroundWorker worker)
        {
            try
            {


                // create reader & open file
                StreamReader tr = new StreamReader(text_filename);


                //extracting the separators from the XML instructions file
                //taking separators
                List<string> separators_lst = new List<string>(_xmlParser.getSeparators2(text_filename));
                string[] separators = separators_lst.ToArray();
                //taking column indexes
                List<string> columnNames = new List<string>(_xmlParser.getColumnNames(text_filename));
                var col_Indexes = from col in columnNames select _xmlParser.getColumnIndex(text_filename, col);

                worker.ReportProgress(1);

                List<List<string>> text = new List<List<string>>();
                List<string> currLine;
                // read a line of text
                string textline;
                while (!tr.EndOfStream)
                {
                    //getting next line from file
                    textline = tr.ReadLine();
                    //parsing curent text line and adding it to list
                    currLine = ParseTextLine(textline, separators);

                    if (currLine.Count < col_Indexes.Count())//protection against empty lines or lines with missing values. The line is ignorred!
                        continue;

                    //taking only the specified columns
                    currLine = SelectColumns(currLine, col_Indexes);

                    //adding the line to the list<list>.
                    text.Add(currLine);

                    //progress bar step
                    worker.ReportProgress(1);

                }

                // close the stream
                tr.Close();
                return text;
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception occured");
                Console.WriteLine(e.Message);
                return null;
            }
        }




        /// <summary>
        /// gets the line from the text and then separates it using given separators  
        /// </summary>
        /// <param name="text"></param>
        /// <returns>arrList of words, representing the query</returns>
        private List<string> ParseTextLine(string text, string[] separators)
        {

            // Split To Word list

            string[] allWordsInText;
            // get all words in text
            allWordsInText = text.Split(separators, StringSplitOptions.RemoveEmptyEntries);

            //entering each query word into  the list
            List<string> wordsList = new List<string>(allWordsInText);


            return wordsList;

        }
        /// <summary>
        /// gets the line from the text and then picks selected columns  using given indexes  
        /// </summary>
        /// <param name="line">full line of text</param>
        /// <param name="cols">list of column indexes to take from the line</param>
        /// <returns></returns>
        private List<string> SelectColumns(List<string> line, IEnumerable<int> cols)
        {

            int count = line.Count;
            for (int i = 0; i < count; i++)
            {
                if (!cols.Contains(i) && i < line.Count)
                {
                    line.RemoveAt(i);

                }
            }

            return line;



        }
    }
}
